﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace Kea
{
    #region 2 Joined
    public struct Row<T1, T2> { public T1 V1; public T2 V2; }

    public abstract class DataPlanJoinedRoot<T1, TJ> : DataPlanJoinedBase<T1, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, TJ> OrderByProtected<TKey>(Func<T1, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<T1, TJ>, TKey>(Comparer, p => keySelector(p.P1, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, TJ> : DataPlanJoinedRoot<T1, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, TJ, TResult> GetJoin<TResult>(Func<T1, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, TJ>() { V1 = p.P1, V2 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2)
            };
        }

        public DataPlanJoined<T1, TJ> Where(Func<T1, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<T1, TJ>>(p => filter(p.P1, p.P2), Filters)
            };
        }

        public DataPlanJoinedOrdered<T1, TJ> OrderBy<TKey>(Func<T1, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, TJ> OrderByDescending<TKey>(Func<T1, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, TJ> : DataPlanJoinedRoot<T1, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, TJ> ThenBy<TKey>(Func<T1, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, TJ> ThenByDescending<TKey>(Func<T1, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion





    #region 3 Joined

    public struct Row<T1, T2, T3> { public T1 V1; public T2 V2; public T3 V3;  }
    public abstract class DataPlanJoinedRoot<T1, T2, TJ> : DataPlanJoinedBase<Row<T1, T2>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, TJ> OrderByProtected<TKey>(Func<T1, T2, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, TJ> : DataPlanJoinedRoot<T1, T2, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, TJ> Where(Func<T1, T2, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, TJ, TResult> GetJoin<TResult>(Func<T1, T2, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, TJ> OrderBy<TKey>(Func<T1, T2, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, TJ> OrderByDescending<TKey>(Func<T1, T2, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, TJ> : DataPlanJoinedRoot<T1, T2, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, TJ> ThenBy<TKey>(Func<T1, T2, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, TJ> ThenByDescending<TKey>(Func<T1, T2, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 4 Joined

    public struct Row<T1, T2, T3, T4> { public T1 V1; public T2 V2; public T3 V3; public T4 V4;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, TJ> : DataPlanJoinedBase<Row<T1, T2, T3>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, TJ> : DataPlanJoinedRoot<T1, T2, T3, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, TJ> Where(Func<T1, T2, T3, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, T3, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, T3, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, T3, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, T3, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, T3, TJ, TResult> GetJoin<TResult>(Func<T1, T2, T3, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, T3, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, T3, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P1.V3, V4 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3, rt.V4)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, T3, TJ> OrderBy<TKey>(Func<T1, T2, T3, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, TJ> : DataPlanJoinedRoot<T1, T2, T3, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, TJ> ThenBy<TKey>(Func<T1, T2, T3, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 5 Joined
    public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public struct Row<T1, T2, T3, T4, T5> { public T1 V1; public T2 V2; public T3 V3; public T4 V4; public T5 V5;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, T4, TJ> : DataPlanJoinedBase<Row<T1, T2, T3, T4>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, T4, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, T4, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, T4, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3, T4>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, T4, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, T4, TJ> Where(Func<T1, T2, T3, T4, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, T4, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3, T4>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, T3, T4, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, T3, T4, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, T3, T4, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, T3, T4, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, T3, T4, TJ, TResult> GetJoin<TResult>(Func<T1, T2, T3, T4, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, T3, T4, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, T3, T4, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P1.V3, V4 = p.P1.V4, V5 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3, rt.V4, rt.V5)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> OrderBy<TKey>(Func<T1, T2, T3, T4, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, T4, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> ThenBy<TKey>(Func<T1, T2, T3, T4, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, T4, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 6 Joined
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public struct Row<T1, T2, T3, T4, T5, T6> { public T1 V1; public T2 V2; public T3 V3; public T4 V4; public T5 V5; public T6 V6;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, T4, T5, TJ> : DataPlanJoinedBase<Row<T1, T2, T3, T4, T5>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, T4, T5, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, T4, T5, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3, T4, T5>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, T4, T5, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, T4, T5, TJ> Where(Func<T1, T2, T3, T4, T5, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3, T4, T5>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, T3, T4, T5, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, T3, T4, T5, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, T3, T4, T5, TJ, TResult> GetJoin<TResult>(Func<T1, T2, T3, T4, T5, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, T3, T4, T5, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P1.V3, V4 = p.P1.V4, V5 = p.P1.V5, V6 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3, rt.V4, rt.V5, rt.V6)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> OrderBy<TKey>(Func<T1, T2, T3, T4, T5, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, T4, T5, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> ThenBy<TKey>(Func<T1, T2, T3, T4, T5, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, T4, T5, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 7 Joined
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public struct Row<T1, T2, T3, T4, T5, T6, T7> { public T1 V1; public T2 V2; public T3 V3; public T4 V4; public T5 V5; public T6 V6; public T7 V7;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, TJ> : DataPlanJoinedBase<Row<T1, T2, T3, T4, T5, T6>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, T4, T5, T6, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, T4, T5, T6, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3, T4, T5, T6>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ> Where(Func<T1, T2, T3, T4, T5, T6, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3, T4, T5, T6>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, T3, T4, T5, T6, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, T3, T4, T5, T6, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ, TResult> GetJoin<TResult>(Func<T1, T2, T3, T4, T5, T6, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, T6, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, T3, T4, T5, T6, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P1.V3, V4 = p.P1.V4, V5 = p.P1.V5, V6 = p.P1.V6, V7 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3, rt.V4, rt.V5, rt.V6, rt.V7)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> OrderBy<TKey>(Func<T1, T2, T3, T4, T5, T6, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> ThenBy<TKey>(Func<T1, T2, T3, T4, T5, T6, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 8 Joined
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    public struct Row<T1, T2, T3, T4, T5, T6, T7, T8> { public T1 V1; public T2 V2; public T3 V3; public T4 V4; public T5 V5; public T6 V6; public T7 V7; public T8 V8;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, TJ> : DataPlanJoinedBase<Row<T1, T2, T3, T4, T5, T6, T7>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3, T4, T5, T6, T7>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ> Where(Func<T1, T2, T3, T4, T5, T6, T7, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3, T4, T5, T6, T7>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P2), Filters)
            };
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ, TJNew> Join<TJNew>(DataPlanJoinableBase<TJNew> dataPlan, Func<T1, T2, T3, T4, T5, T6, T7, TJ, object> keyProvider) where TJNew : TableReaderWriter<TJNew>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinable());
        }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ, TLookupResult> Lookup<TLK, TLookupResult>(DataPlanLookupable<TLK, TLookupResult> dataPlan, Func<T1, T2, T3, T4, T5, T6, T7, TJ, object> keyProvider) where TLK : TableReaderWriter<TLK>, new()
        {
            return GetJoin(keyProvider, dataPlan.GetJoinableLookup());
        }

        private DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ, TResult> GetJoin<TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, object> keyProvider, Func<Joinable<TResult>> joinProvider)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, TJ, TResult>()
            {
                TheEnumerable = base.Select(p => new Row<T1, T2, T3, T4, T5, T6, T7, TJ>() { V1 = p.P1.V1, V2 = p.P1.V2, V3 = p.P1.V3, V4 = p.P1.V4, V5 = p.P1.V5, V6 = p.P1.V6, V7 = p.P1.V7, V8 = p.P2 }),
                JoinProvider = joinProvider,
                ReaderKeyProvider = rt => keyProvider(rt.V1, rt.V2, rt.V3, rt.V4, rt.V5, rt.V6, rt.V7, rt.V8)
            };
        }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> OrderBy<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> ThenBy<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
    #region 9 Joined
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
    public struct Row<T1, T2, T3, T4, T5, T6, T7, T8, T9> { public T1 V1; public T2 V2; public T3 V3; public T4 V4; public T5 V5; public T6 V6; public T7 V7; public T8 V8; public T9 V9;  }
    public abstract class DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, T8, TJ> : DataPlanJoinedBase<Row<T1, T2, T3, T4, T5, T6, T7, T8>, TJ>
    {
        public IEnumerable<TResult> Select<TResult>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TResult> selector)
        {
            return base.Select(p => selector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P1.V8, p.P2));
        }

        protected DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> OrderByProtected<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TKey> keySelector, bool asc)
        {
            return new DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ>
            {
                TheEnumerable = TheEnumerable,
                Comparer = new KeyComparerProvider<Pair<Row<T1, T2, T3, T4, T5, T6, T7, T8>, TJ>, TKey>(Comparer, p => keySelector(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P1.V8, p.P2), asc),
                Filters = Filters,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider
            };
        }
    }

    public class DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, T8, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, T8, TJ>
    {
        internal DataPlanJoined() { }

        public DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, T8, TJ> Where(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, bool> filter)
        {
            return new DataPlanJoined<T1, T2, T3, T4, T5, T6, T7, T8, TJ>()
            {
                TheEnumerable = TheEnumerable,
                JoinProvider = JoinProvider,
                ReaderKeyProvider = ReaderKeyProvider,
                Comparer = Comparer,
                Filters = new LinkedFilter<Pair<Row<T1, T2, T3, T4, T5, T6, T7, T8>, TJ>>(p => filter(p.P1.V1, p.P1.V2, p.P1.V3, p.P1.V4, p.P1.V5, p.P1.V6, p.P1.V7, p.P1.V8, p.P2), Filters)
            };
        }


        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> OrderBy<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> OrderByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }

    }

    public class DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> : DataPlanJoinedRoot<T1, T2, T3, T4, T5, T6, T7, T8, TJ>
    {
        internal DataPlanJoinedOrdered() { }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> ThenBy<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanJoinedOrdered<T1, T2, T3, T4, T5, T6, T7, T8, TJ> ThenByDescending<TKey>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TJ, TKey> keySelector) { return OrderByProtected(keySelector, false); }
    }
    #endregion
}
